package channelScheduler

import (
	"fmt"
	"gitee.com/fierce_wolf/go-fox-edge-channel-common/channelAPI"
	"gitee.com/fierce_wolf/go-fox-edge-channel-common/channelStatus"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEntityManager"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEnv"
	"gitee.com/fierce_wolf/go-fox-edge-common/commLogger"
	"gitee.com/fierce_wolf/go-fox-edge-common/commRedisService"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Differ"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/String"
	"gitee.com/fierce_wolf/go-fox-edge-common/edgeEntity"
	"time"
)

type channelManageScheduler struct {
	updateTime       int64
	channelEntityMap map[string]*edgeEntity.ChannelEntity
}

// Scheduler 创建一个线程
func (e *channelManageScheduler) Scheduler() {
	go e.scheduler()
}

// 线程函数
func (e *channelManageScheduler) scheduler() {
	for true {
		time.Sleep(1 * time.Second)
		if !commEntityManager.EntityManager.Initialized {
			continue
		}

		// 检测：是否实例化接口
		if channelAPI.Service.IOpenChannel == nil || channelAPI.Service.ICloseChannel == nil {
			continue
		}

		// 检测：数据是否更新
		updateTime := commRedisService.GetUpdateTime(edgeEntity.Type.ChannelEntity.Type())
		if e.updateTime == updateTime {
			continue
		}
		e.updateTime = updateTime

		// 获得全体ChannelEntity
		entityList, err := commRedisService.GetEntityMap(edgeEntity.Type.ChannelEntity.Type())
		if err != nil {
			continue
		}

		// 处理数据
		channelType := commEnv.Service.ModelName
		channelMap := make(map[string]*edgeEntity.ChannelEntity)
		for _, entity := range entityList {
			channelEntity := entity.(*edgeEntity.ChannelEntity)
			if channelEntity.ChannelType != channelType {
				continue
			}

			channelMap[channelEntity.ChannelName] = channelEntity
		}

		// 比较差异
		addList := make(map[string]interface{})
		delList := make(map[string]interface{})
		eqlList := make(map[string]interface{})
		Differ.Set.DifferByKey(e.channelEntityMap, channelMap, &addList, &delList, &eqlList)

		for key := range addList {
			e.openCh(channelMap[key])
		}

		for key := range delList {
			e.closeCh(e.channelEntityMap[key])
		}

		// 重新打开通道
		for key := range eqlList {
			oldEntity := e.channelEntityMap[key]
			newEntity := channelMap[key]

			// 检测：配置内容是否发生了变化
			if (String.GetMapString(newEntity.ChannelParam) == String.GetMapString(oldEntity.ChannelParam)) && (String.GetMapString(newEntity.ExtendParam) == String.GetMapString(oldEntity.ExtendParam)) {
				continue
			}

			e.closeCh(oldEntity)
			e.openCh(newEntity)
		}
	}
}

func (e *channelManageScheduler) openCh(channelEntity *edgeEntity.ChannelEntity) {
	if channelEntity == nil {
		return
	}

	err := channelAPI.Service.OpenChannel(channelEntity.ChannelName, channelEntity.ChannelParam)
	if err != nil {
		message := fmt.Sprintf("通道打开失败:%v: %v", channelEntity.ChannelName, err)
		commLogger.Error(message)

		channelStatus.Open.UpdateOpenStatus(channelEntity.ChannelName, false)
	} else {
		e.channelEntityMap[channelEntity.ChannelName] = channelEntity

		message := fmt.Sprintf("通道打开成功:%v", channelEntity.ChannelName)
		commLogger.Info(message)

		channelStatus.Open.UpdateOpenStatus(channelEntity.ChannelName, true)
	}
}
func (e *channelManageScheduler) closeCh(channelEntity *edgeEntity.ChannelEntity) {
	if channelEntity == nil {
		return
	}

	err := channelAPI.Service.CloseChannel(channelEntity.ChannelName, channelEntity.ChannelParam)
	if err != nil {
		message := fmt.Sprintf("通道关闭失败:%v: %v", channelEntity.ChannelName, err)
		commLogger.Error(message)
	} else {
		delete(e.channelEntityMap, channelEntity.ChannelName)

		message := fmt.Sprintf("通道关闭成功:%v", channelEntity.ChannelName)
		commLogger.Info(message)

		channelStatus.Open.UpdateOpenStatus(channelEntity.ChannelName, false)
	}
}

func (e *channelManageScheduler) openChannel(channelEntity *edgeEntity.ChannelEntity) {
	channelAPI.Service.OpenChannel(channelEntity.ChannelName, channelEntity.ChannelParam)
	e.channelEntityMap[channelEntity.ChannelName] = channelEntity
}

func (e *channelManageScheduler) closeChannel(channelEntity *edgeEntity.ChannelEntity) {
	channelAPI.Service.CloseChannel(channelEntity.ChannelName, channelEntity.ChannelParam)
	delete(e.channelEntityMap, channelEntity.ChannelName)
}
